4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
16 namespace Microsoft
.JScript
{
18 using Microsoft
.JScript
.Vsa
;
20 using System
.Reflection
;
21 using System
.Reflection
.Emit
;
23 public class StrictEquality
: BinaryOp
{
25 internal StrictEquality(Context context
, AST operand1
, AST operand2
, JSToken operatorTok
)
26 : base(context
, operand1
, operand2
, operatorTok
) {
29 internal override Object
Evaluate(){
30 bool result
= JScriptStrictEquals(this.operand1
.Evaluate(), this.operand2
.Evaluate(), VsaEngine
.executeForJSEE
);
31 if (this.operatorTok
== JSToken
.StrictEqual
)
37 public static bool JScriptStrictEquals(Object v1
, Object v2
){
38 return StrictEquality
.JScriptStrictEquals(v1
, v2
, false);
41 internal static bool JScriptStrictEquals(Object v1
, Object v2
, bool checkForDebuggerObjects
){
42 IConvertible ic1
= Convert
.GetIConvertible(v1
);
43 IConvertible ic2
= Convert
.GetIConvertible(v2
);
44 TypeCode t1
= Convert
.GetTypeCode(v1
, ic1
);
45 TypeCode t2
= Convert
.GetTypeCode(v2
, ic2
);
46 return StrictEquality
.JScriptStrictEquals(v1
, v2
, ic1
, ic2
, t1
, t2
, checkForDebuggerObjects
);
49 internal static bool JScriptStrictEquals(Object v1
, Object v2
, IConvertible ic1
, IConvertible ic2
, TypeCode t1
, TypeCode t2
, bool checkForDebuggerObjects
){
51 case TypeCode
.Empty
: return t2
== TypeCode
.Empty
;
53 if (v1
== v2
) return true;
54 if (v1
is Missing
|| v1
is System
.Reflection
.Missing
) v1
= null;
55 if (v1
== v2
) return true;
56 if (v2
is Missing
|| v2
is System
.Reflection
.Missing
) v2
= null;
58 case TypeCode
.DBNull
: return t2
== TypeCode
.DBNull
;
59 case TypeCode
.Boolean
: return t2
== TypeCode
.Boolean
&& ic1
.ToBoolean(null) == ic2
.ToBoolean(null);
62 Char ch
= ic1
.ToChar(null);
64 case TypeCode
.Char
: return ch
== ic2
.ToChar(null);
71 case TypeCode
.Int64
: return ch
== ic2
.ToInt64(null);
72 case TypeCode
.UInt64
: return ch
== ic2
.ToUInt64(null);
74 case TypeCode
.Double
: return ch
== ic2
.ToDouble(null);
75 case TypeCode
.Decimal
: return ((Decimal
)(int)ch
) == ic2
.ToDecimal(null);
77 String str
= ic2
.ToString(null);
78 return str
.Length
== 1 && ch
== str
[0];
83 SByte sb1
= ic1
.ToSByte(null);
85 case TypeCode
.Char
: return sb1
== ic2
.ToChar(null);
92 case TypeCode
.Int64
: return sb1
== ic2
.ToInt64(null);
93 case TypeCode
.UInt64
: return sb1
>= 0 && ((UInt64
)sb1
) == ic2
.ToUInt64(null);
94 case TypeCode
.Single
: return sb1
== ic2
.ToSingle(null);
95 case TypeCode
.Double
: return sb1
== ic2
.ToDouble(null);
96 case TypeCode
.Decimal
: return ((Decimal
)sb1
) == ic2
.ToDecimal(null);
101 Byte b1
= ic1
.ToByte(null);
103 case TypeCode
.Char
: return b1
== ic2
.ToChar(null);
107 case TypeCode
.UInt16
:
109 case TypeCode
.UInt32
:
110 case TypeCode
.Int64
: return b1
== ic2
.ToInt64(null);
111 case TypeCode
.UInt64
: return b1
== ic2
.ToUInt64(null);
112 case TypeCode
.Single
: return b1
== ic2
.ToSingle(null);
113 case TypeCode
.Double
: return b1
== ic2
.ToDouble(null);
114 case TypeCode
.Decimal
: return ((Decimal
)b1
) == ic2
.ToDecimal(null);
119 Int16 s1
= ic1
.ToInt16(null);
121 case TypeCode
.Char
: return s1
== ic2
.ToChar(null);
125 case TypeCode
.UInt16
:
127 case TypeCode
.UInt32
:
128 case TypeCode
.Int64
: return s1
== ic2
.ToInt64(null);
129 case TypeCode
.UInt64
: return s1
>= 0 && ((UInt64
)s1
) == ic2
.ToUInt64(null);
130 case TypeCode
.Single
: return s1
== ic2
.ToSingle(null);
131 case TypeCode
.Double
: return s1
== ic2
.ToDouble(null);
132 case TypeCode
.Decimal
: return ((Decimal
)s1
) == ic2
.ToDecimal(null);
136 case TypeCode
.UInt16
:
137 UInt16 us1
= ic1
.ToUInt16(null);
139 case TypeCode
.Char
: return us1
== ic2
.ToChar(null);
143 case TypeCode
.UInt16
:
145 case TypeCode
.UInt32
:
146 case TypeCode
.Int64
: return us1
== ic2
.ToInt64(null);
147 case TypeCode
.UInt64
: return us1
== ic2
.ToUInt64(null);
148 case TypeCode
.Single
: return us1
== ic2
.ToSingle(null);
149 case TypeCode
.Double
: return us1
== ic2
.ToDouble(null);
150 case TypeCode
.Decimal
: return ((Decimal
)us1
) == ic2
.ToDecimal(null);
155 Int32 i1
= ic1
.ToInt32(null);
157 case TypeCode
.Char
: return i1
== ic2
.ToChar(null);
161 case TypeCode
.UInt16
:
163 case TypeCode
.UInt32
:
164 case TypeCode
.Int64
: return i1
== ic2
.ToInt64(null);
165 case TypeCode
.UInt64
: return i1
>= 0 && ((UInt64
)i1
) == ic2
.ToUInt64(null);
166 case TypeCode
.Single
: return i1
== ic2
.ToSingle(null);
167 case TypeCode
.Double
: return i1
== ic2
.ToDouble(null);
168 case TypeCode
.Decimal
: return ((Decimal
)i1
) == ic2
.ToDecimal(null);
172 case TypeCode
.UInt32
:
173 UInt32 ui1
= ic1
.ToUInt32(null);
175 case TypeCode
.Char
: return ui1
== ic2
.ToChar(null);
179 case TypeCode
.UInt16
:
181 case TypeCode
.UInt32
:
182 case TypeCode
.Int64
: return ui1
== ic2
.ToInt64(null);
183 case TypeCode
.UInt64
: return ui1
== ic2
.ToUInt64(null);
184 case TypeCode
.Single
: return ui1
== ic2
.ToSingle(null);
185 case TypeCode
.Double
: return ui1
== ic2
.ToDouble(null);
186 case TypeCode
.Decimal
: return ((Decimal
)ui1
) == ic2
.ToDecimal(null);
191 Int64 l1
= ic1
.ToInt64(null);
193 case TypeCode
.Char
: return l1
== ic2
.ToChar(null);
197 case TypeCode
.UInt16
:
199 case TypeCode
.UInt32
:
200 case TypeCode
.Int64
: return l1
== ic2
.ToInt64(null);
201 case TypeCode
.UInt64
: return l1
>= 0 && ((UInt64
)l1
) == ic2
.ToUInt64(null);
202 case TypeCode
.Single
: return l1
== ic2
.ToSingle(null);
203 case TypeCode
.Double
: return l1
== ic2
.ToDouble(null);
204 case TypeCode
.Decimal
: return ((Decimal
)l1
) == ic2
.ToDecimal(null);
208 case TypeCode
.UInt64
:
209 UInt64 ul1
= ic1
.ToUInt64(null);
211 case TypeCode
.Char
: return ul1
== ic2
.ToChar(null);
215 case TypeCode
.UInt16
:
217 case TypeCode
.UInt32
:
219 l1
= ic2
.ToInt64(null);
220 return l1
>= 0 && ul1
== (UInt64
)l1
;
221 case TypeCode
.UInt64
: return ul1
== ic2
.ToUInt64(null);
222 case TypeCode
.Single
: return ul1
== ic2
.ToSingle(null);
223 case TypeCode
.Double
: return ul1
== ic2
.ToDouble(null);
224 case TypeCode
.Decimal
: return ((Decimal
)ul1
) == ic2
.ToDecimal(null);
228 case TypeCode
.Single
:
229 Single f1
= ic1
.ToSingle(null);
231 case TypeCode
.Char
: return f1
== ic2
.ToChar(null);
235 case TypeCode
.UInt16
:
237 case TypeCode
.UInt32
:
238 case TypeCode
.Int64
: return f1
== ic2
.ToInt64(null);
239 case TypeCode
.UInt64
: return f1
== ic2
.ToUInt64(null);
240 case TypeCode
.Single
: return f1
== ic2
.ToSingle(null);
241 case TypeCode
.Double
: return f1
== ic2
.ToSingle(null);
242 case TypeCode
.Decimal
: return ((Decimal
)f1
) == ic2
.ToDecimal(null);
246 case TypeCode
.Double
:
247 Double d1
= ic1
.ToDouble(null);
249 case TypeCode
.Char
: return d1
== ic2
.ToChar(null);
253 case TypeCode
.UInt16
:
255 case TypeCode
.UInt32
:
256 case TypeCode
.Int64
: return d1
== ic2
.ToInt64(null);
257 case TypeCode
.UInt64
: return d1
== ic2
.ToUInt64(null);
258 case TypeCode
.Single
: return ((float)d1
) == ic2
.ToSingle(null);
259 case TypeCode
.Double
: return d1
== ic2
.ToDouble(null);
260 case TypeCode
.Decimal
: return ((Decimal
)d1
) == ic2
.ToDecimal(null);
264 case TypeCode
.Decimal
:
265 Decimal de1
= ic1
.ToDecimal(null);
267 case TypeCode
.Char
: return de1
== (Decimal
)(int)ic2
.ToChar(null);
271 case TypeCode
.UInt16
:
273 case TypeCode
.UInt32
:
274 case TypeCode
.Int64
: return de1
== ic2
.ToInt64(null);
275 case TypeCode
.UInt64
: return de1
== ic2
.ToUInt64(null);
276 case TypeCode
.Single
: return de1
== (Decimal
)ic2
.ToSingle(null);
277 case TypeCode
.Double
: return de1
== (Decimal
)ic2
.ToDouble(null);
278 case TypeCode
.Decimal
: return de1
== ic2
.ToDecimal(null);
282 case TypeCode
.DateTime
: return t2
== TypeCode
.DateTime
&& ic1
.ToDateTime(null) == ic2
.ToDateTime(null);
283 case TypeCode
.String
:
284 if (t2
== TypeCode
.Char
){
285 String str
= ic1
.ToString(null);
286 return str
.Length
== 1 && str
[0] == ic2
.ToChar(null);
288 return t2
== TypeCode
.String
&& (v1
== v2
|| ic1
.ToString(null).Equals(ic2
.ToString(null)));
290 return false; //should never get here
293 internal override IReflect
InferType(JSField inference_target
){
294 return Typeob
.Boolean
;
297 internal override void TranslateToConditionalBranch(ILGenerator il
, bool branchIfTrue
, Label label
, bool shortForm
){
298 Type t1
= Convert
.ToType(this.operand1
.InferType(null));
299 Type t2
= Convert
.ToType(this.operand2
.InferType(null));
300 if (this.operand1
is ConstantWrapper
)
301 if (this.operand1
.Evaluate() == null) t1
= Typeob
.Empty
;
302 if (this.operand2
is ConstantWrapper
)
303 if (this.operand2
.Evaluate() == null) t2
= Typeob
.Empty
;
304 if (t1
!= t2
&& t1
.IsPrimitive
&& t2
.IsPrimitive
){
305 if (t1
== Typeob
.Single
)
307 else if (t2
== Typeob
.Single
)
309 else if (Convert
.IsPromotableTo(t2
, t1
))
311 else if (Convert
.IsPromotableTo(t1
, t2
))
314 bool nonPrimitive
= true;
315 if (t1
== t2
&& t1
!= Typeob
.Object
){
316 // Operand types are equal and not Object - need to compare values only. Primitive
317 // values get compared with IL instructions; other values including value types
318 // get compared with Object.Equals. String is special cased for perf.
322 this.operand1
.TranslateToIL(il
, t
);
323 this.operand2
.TranslateToIL(il
, t
);
324 if (t1
== Typeob
.String
)
325 il
.Emit(OpCodes
.Call
, CompilerGlobals
.stringEqualsMethod
);
326 else if (!t1
.IsPrimitive
)
327 il
.Emit(OpCodes
.Callvirt
, CompilerGlobals
.equalsMethod
);
329 nonPrimitive
= false;
330 }else if (t1
== Typeob
.Empty
){
331 this.operand2
.TranslateToIL(il
, Typeob
.Object
);
332 branchIfTrue
= !branchIfTrue
;
333 }else if (t2
== Typeob
.Empty
){
334 this.operand1
.TranslateToIL(il
, Typeob
.Object
);
335 branchIfTrue
= !branchIfTrue
;
337 this.operand1
.TranslateToIL(il
, Typeob
.Object
);
338 this.operand2
.TranslateToIL(il
, Typeob
.Object
);
339 il
.Emit(OpCodes
.Call
, CompilerGlobals
.jScriptStrictEqualsMethod
);
342 if (this.operatorTok
== JSToken
.StrictEqual
)
344 il
.Emit(shortForm
? OpCodes
.Brtrue_S
: OpCodes
.Brtrue
, label
);
346 il
.Emit(shortForm
? OpCodes
.Beq_S
: OpCodes
.Beq
, label
);
349 il
.Emit(shortForm
? OpCodes
.Brfalse_S
: OpCodes
.Brfalse
, label
);
351 il
.Emit(shortForm
? OpCodes
.Bne_Un_S
: OpCodes
.Bne_Un
, label
);
353 if (this.operatorTok
== JSToken
.StrictEqual
)
355 il
.Emit(shortForm
? OpCodes
.Brfalse_S
: OpCodes
.Brfalse
, label
);
357 il
.Emit(shortForm
? OpCodes
.Bne_Un_S
: OpCodes
.Bne_Un
, label
);
360 il
.Emit(shortForm
? OpCodes
.Brtrue_S
: OpCodes
.Brtrue
, label
);
362 il
.Emit(shortForm
? OpCodes
.Beq_S
: OpCodes
.Beq
, label
);
367 internal override void TranslateToIL(ILGenerator il
, Type rtype
){
368 Label true_label
= il
.DefineLabel();
369 Label done_label
= il
.DefineLabel();
370 this.TranslateToConditionalBranch(il
, true, true_label
, true);
371 il
.Emit(OpCodes
.Ldc_I4_0
);
372 il
.Emit(OpCodes
.Br_S
, done_label
);
373 il
.MarkLabel(true_label
);
374 il
.Emit(OpCodes
.Ldc_I4_1
);
375 il
.MarkLabel(done_label
);
376 Convert
.Emit(this, il
, Typeob
.Boolean
, rtype
);